#include "Monitor.h"
#include "Character.h"
#include "Player.h"
#include "PikmenEnemy.h"
#include "Pikmen.h"
#include "Obstacle.h"
#include "CSurface.h"
#include "CApp.h"
#include "Grito.h"

#include <stdlib.h>
#include <math.h>

Monitor::Monitor(){
  oldTimeHeal = 0;
}


//=====GETTERS==============//
vector<Character*> Monitor::GetCharacters(){
  return characters;
}

vector<Obstacle*> Monitor::GetObstacle(){
  return obstacle;
}

vector<Character*> Monitor::GetEnemys(){
  return enemys;
}

Character* Monitor::GetPlayer(){
  return player;
}

//======SETTERS===========//

void Monitor::SetCharacters(vector<Character*> c){
  characters = c;
}

void Monitor::SetObstacle(vector<Obstacle*> o){
  obstacle = o;
}

void Monitor::SetEnemys(vector<Character*>e){
  enemys= e;
}

void Monitor::SetPlayer(Character* p){
  player = p;
}

//=====CONSTRUCTOR==============//
Monitor::Monitor(vector<Character*> ch,vector<Obstacle *>  ob,vector<Character *> en,Character *p){
  characters = ch;
  obstacle = ob;
  enemys =en;
  player = p;
}

void Monitor::isDeadAnyone(){
  Character *aux;
  for (int i = 0, n = characters.size(); i < n;i++){
    if (characters[i]->isDead()){
      aux = characters[i];
      characters[i]->k->position[0] = 7000;
      characters[i]->k->position[1] = 7000;
//    characters.erase(characters.begin()+i);
//    i--;
    }
  }

  for (int i = 0, n = enemys.size(); i < n;i++){
    if (enemys[i]->isDead()){
      aux = enemys[i];
      enemys[i]->k->position[0] = 7000;
      enemys[i]->k->position[1] = 7000;
      enemys[i]->estaFrito = true;
//    enemys.erase(enemys.begin()+i);
//    i--;
    }
  }

  if(player->isDead()){
    cout << endl
      << "*****************" << endl
      << "**   Perdiste  **" << endl
      << "*****************" << endl << endl;
    exit(EXIT_SUCCESS);
  }
  actual = 0;
  for (int i =0 , n = enemys.size();i <n ;i++){
    Kinematic *b = enemys[i]->getKinematic();
    if ((b->position[0] > 5000) && (b->position[1] > 5000)){
    actual++;
    }
    delete b;
  }
  if (actual== total){
    termino = true;
  }
}

void Monitor::UpdateData(Uint32 current_time,Uint32 old_time){
  vector<Node *>nodes;
  Node *node;
  int i, j, n;
  long current = SDL_GetTicks();

  for(int i=0, n=characters.size(); i<n; i++ ){
    Kinematic * b= characters[i]->getKinematic();
    characters[i]->updateTargetsData();
    characters[i]->OnLoop(current_time-old_time);

    for(int j=0, n=graph_heal.nodes.size(); j<n; j++){
      Node *node = graph_heal.nodes[j];
      float aux[3] = {(*node)[0], (*node)[1], 0};

      restarVectores(aux, b->position, aux);
      if (length(aux) < 52){
        characters[i]->addLife(2);
      }
    }

    // Para evitar que se peguen en la esquina superior
    if(
        isnan(b->position[0]) ||
        isnan(b->position[1]) ||
        isnan(b->position[2]) )
    {
//    characters[i]->k->position[0] = 300;
//    characters[i]->k->position[1] = 350;
//    characters[i]->k->position[2] = 0;

//    characters[i]->k->velocity[0] = 0;
//    characters[i]->k->velocity[1] = 0;
//    characters[i]->k->velocity[2] = 0;

//    characters[i]->k->orientation = 0;
//    characters[i]->k->rotation = 0;
    }

    delete b;
  }
  for(int i=0, n=enemys.size();i<n; i++){
    enemys[i]->updateTargetsData();
    enemys[i]->OnLoop(current_time-old_time);
  }
  this->player->OnLoop(current_time-old_time);

  // Propagar y eliminar olores
  nodes = graph.getNodes();
  for(i=0, n=nodes.size(); i<n; i++){
    node = nodes[i];

    for(j=0; j<(int)node->olores.size(); j++){
      Olor* olor = node->olores[j];

      if(olor->hasExpired()){
        node->olores.erase(node->olores.begin() + j);
        j--;
      } else if(current-olor->oldTimeProp>=olor->propagation){
        Olor *newOlor = new Olor(*olor);

        float _vel[3] = {wind_dir_x, wind_dir_y, 0};
        float _pos[3] = {
          newOlor->position[0] + wind_dir_x,
          newOlor->position[1] + wind_dir_y, 0};
        float*_current = (float *) malloc(sizeof(float)*3);
        float *I = (float *) malloc(sizeof(float)*3);
        float *N = (float *) malloc(sizeof(float)*3);
        int k, n2;

        for(k=0, n2=obstacle.size(); k<n2; k++){
          if( obstacle[k]->collideWith(
                _pos, _vel, &_current, &I, &N)){
            // DEBUG
            // cout << I[0] << ", " << I[1] << endl;
            _pos[0] = _current[0] + olor->w*N[0];
            _pos[1] = _current[1] + olor->h*N[1];
            _pos[2] = 0;
            break;
          }
        }
        free(_current);
        free(I);
        free(N);

        newOlor->position[0] = _pos[0];
        newOlor->position[1] = _pos[1];
        newOlor->oldTimeProp = current;

        Node *toNode = theApp.findNearestNode(newOlor->position);
        node->olores.erase(node->olores.begin() + j);
        toNode->addOlor(newOlor);
      }
    }
  }
  
  for (int i =0,n = naves.size() ; i < n ;i++){
    naves[i]->updateTargetsData();
    naves[i]->OnLoop(current_time-old_time);
    
  }

  // Cambiar la direccion del viento
  if(current-wind_dir_oldTime>=wind_dir_time){
    theApp.changeWind();
    wind_dir_oldTime = current;
  }

  // propagar el sonido
  for(i=0; i<(int)gritos.size(); i++){
    Grito *grito = gritos[i];
    if(grito->hasExpired()){
      gritos.erase(gritos.begin() + i);
      i--;
    } else {
      // DEBUG
//    float _aux[3] = {2, 5, 0};
//    float _aux1[3] = {10, 10, 0};
//    float _aux2[3] = {0, 0, 0};
//    float _aux3[3] = {0, 10, 0};
//    cout << "Otra: " << pointIntTriangle(_aux, _aux1, _aux2, _aux3) << endl;
//    cout << "Verificando: " << grito->isIn(_aux) << endl;
    }
  }


}

void Monitor::CleanUp(){
  for(int i=0, n=characters.size(); i<n; i++ ){
    characters[i]->OnCleanup();
    delete characters[i];
  }
}

void Monitor::OnInit(){
 //==============Inicializamos al Player=============/
  player = new Player();
  player->OnInit();

}

void Monitor::addPlatform(float p[3],int w, int h){
  Platform *add = new Platform();
  add->position[0] = p[0];
  add->position[1] = p[1];
  add->position[2] = p[2];
  add->width =w;
  add->height =h;
  platforms.push_back(add);
}


Platform* Monitor::getPlatform(float p[3]){
  for (int i =0, n = platforms.size(); i < n; i++){
    if(pointIntRec(p,platforms[i]))
      return platforms[i];
  }
  return NULL;
}

void Monitor:: Yells(Kinematic *k){
  float aux[3];
  for (int i = 0, n = characters.size() ; i <  n; i++){
    Kinematic * b = characters[i]->getKinematic();
    restarVectores(k->position,b->position,aux);
    if (length(aux) <=900){
      characters[i]->processYells(k,true);
    }
    delete b;
  }
  for (int i = 0, n = enemys.size() ; i < n ; i++){
    Kinematic * b = enemys[i]->getKinematic();
    restarVectores(k->position,b->position,aux);
    if (length(aux) <=5000){
      enemys[i]->processYells(k,false);
    }
    delete b;
  }
}

void Monitor::addPikmen(int x1, int y1){
   Pikmen* pikmen = new Pikmen();
    pikmen->OnInit(&characters,&obstacle,&enemys,x1,y1,player);
     characters.push_back(pikmen);
}

void Monitor::addEnemy(int x1, int y1){
   PikmenEnemy *pikmenE= new PikmenEnemy();
    pikmenE->OnInit(&characters,&obstacle,x1,y1,player);
     enemys.push_back(pikmenE);
}

vector<Character*>* Monitor::GetEnemysApun(){
  return &enemys;
}
